package br.com.advocacia.dao.generico;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;

@Repository
public class DaoGenerico<T> implements Serializable {

	private static final Log LOG = LogFactory.getLog(DaoGenerico.class);

	@PersistenceContext
	private EntityManager entityManager;

	private static final long serialVersionUID = 1L;

	public void adicionar(T entidade) throws Exception {
		try {

			entityManager.persist(entidade);

		} catch (Exception e) {
			LOG.error("Erro ao incluir a Entidade " + entidade.getClass(), 	e.getCause());
			throw new Exception("Erro ao incluir a Entidade ");
		}
	}

	public void editar(T entidade) throws Exception {
		try {
			entityManager.merge(entidade);
		} catch (Exception e) {
			LOG.error("Erro ao atualizar" + entidade.getClass(), e.getCause());
			throw new Exception("Erro ao atualizar ");
		}
	}

	public void remover(Class<T> clazz, long idEntidade) throws Exception {
		Object find = entityManager.find(clazz, idEntidade);

		try {
			entityManager.remove(find);
		} catch (Exception e) {
			LOG.error("Erro ao excluir " + clazz.getClass(), e.getCause());
			throw new Exception("Erro ao excluir ");
		}
	}

	@SuppressWarnings({ "unchecked", "hiding" })
	public <T> T obterPorId(Class<T> classe, Long idEntidade) throws Exception {
		try {

			if (idEntidade == null || idEntidade == 0) {
				throw new Exception("Id da entidade não fornecido.");
			}

			StringBuilder sqlEntidade = new StringBuilder();
			sqlEntidade.append(" Select e from " + classe.getSimpleName() + " e ");
			sqlEntidade.append(" where e.id = :idEntidade");

			Query queryEntidade = getSession().createQuery(sqlEntidade.toString());

			queryEntidade.setParameter("idEntidade", idEntidade);

			return (T) queryEntidade.uniqueResult();

		} catch (Exception e) {
			LOG.error("Erro ao excluir " + classe.getClass(), e.getCause());
			throw new Exception("Não foi possível pesquisar o registro ");
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> buscarTodos(Class<T> classe, String campoOrdenacao) throws Exception {
		String nomeClasse = classe.getSimpleName();
		try {
			Query query = getSession().createQuery("select e from "	+ nomeClasse + " e order by e." + campoOrdenacao + " asc ");
			List<T> lista = query.list();

			return lista;
		} catch (Exception e) {
			LOG.error("Não foi possível buscar a lista total. " + classe.getClass(), e.getCause());
			throw new Exception("Não foi possível pesquisar o registro ");
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<T> buscarPorCampo(Class<T> classe, String campo, Object valor) throws Exception {
		try {
			StringBuilder sqlCompleto = new StringBuilder();
			String nomeClasse = classe.getSimpleName();
			
			sqlCompleto.append(" Select e from " + nomeClasse + " e");
			sqlCompleto.append(" where " + campo + " like '%"+valor+"%' ") ;
			
			Query query = getSession().createQuery(sqlCompleto.toString());
			List<T> lista = query.list();
			
			return lista;
			
		} catch (Exception e) {
			LOG.error("Não foi possível buscar a lista total. " + classe.getClass(), e.getCause());
			throw new Exception("Não foi possível pesquisar o registro ");
		}
	}
	
	

	public void cadastroEmLote(List<T> listaEntidade) throws Exception {
		try {
			for (T entidade : listaEntidade) {
				entityManager.persist(entidade);
			}
		} catch (Exception e) {
			LOG.error("Não foi possível buscar a lista total. ", e.getCause());
			throw new Exception("Não foi possível pesquisar o registro ");
		}
	}

	public EntityManager obterEntityManager() {
		return this.entityManager;
	}

	public Session getSession() {
		Session session = (Session) entityManager.getDelegate();

		if (!session.isOpen()) {
			session = session.getSessionFactory().openSession();
		}

		return session;
	}

}
